// A map of event types and their corresponding event handlers.
export type EventHandlerMap<Events, Handler> = Map<keyof Events | '*', Handler[]>;

type originEventType = string | symbol | number;
type EventTemplate<K extends originEventType, Handler = Function> = {
    [name in K]: Handler | Handler[];
};

// TODO 下个版本的类型输入改为输入一个类型，key 为事件名，value 为 callback 类型
/**
 * @license
 * Copyright 2021 KonghaYao 江夏尧 <dongzhongzhidong@qq.com>
 * SPDX-License-Identifier: MIT
 *
 * @description EventHub 是一个事件处理中心，用于事件的接收与派发，如果有特定的要求，请直接继承 EventHub类创建操作
 */
export default class EventHub<
    EventType extends originEventType,
    H extends Function,
    T = undefined,
    Events = Record<EventType, H>,
> {
    all: EventHandlerMap<Events, H> = new Map();
    bindThis: T | this;
    constructor(template?: EventTemplate<keyof Events, H>, bindThis?: T) {
        this.bindThis = bindThis || this; // 可以指定绑定的 this, 默认是指定为 EventHub 实例
        if (template) this.on(template);
    }

    /**
     * singleOn 是单个事件绑定函数，type 与 handle 函数一一对应
     */
    private singeOn<Key extends keyof Events>(type: Key, handler: H) {
        const handlers = this.all.get(type);
        handlers ? handlers.push(handler) : this.all.set(type, [handler]);
    }
    /**
     * on 函数重载，第一个参数可以为一个事件绑定对象，
     *    on({
     *          eventName: callback,
     *          eventName: [callback]
     *    })
     *    on(type,handler)
     */
    on<Key extends keyof Events>(type: Key, handler: H): void;
    on<Key extends keyof Events>(Template: EventTemplate<Key, H>): void;

    on<Key extends keyof Events>(type: Key | EventTemplate<Key, H>, handler?: H) {
        if (typeof type === 'string' && type !== '*') {
            if (handler instanceof Function) {
                this.singeOn(type as Key, handler);
            } else {
                throw new Error('请绑定事件函数');
            }
        } else if (type instanceof Object) {
            // 在直接赋值为一个
            Object.entries(type).forEach(([key, value]) => {
                if (value instanceof Array) {
                    value.forEach((item) => this.singeOn(key as Key, item));
                } else if (value instanceof Function) {
                    this.singeOn(key as Key, value as H);
                } else {
                    throw new Error('请绑定事件函数');
                }
            });
        } else {
            throw new Error('事件函数数据类型错误');
        }
        return this;
    }

    /**
     * off 函数 type 设置为 '*' 时删除所有函数
     */
    off<Key extends keyof Events>(type: Key, handler: H) {
        if (type === '*') {
            return this.all.clear();
        } else {
            const handlers = this.all.get(type);
            if (handlers && handler) {
                return handlers.splice(handlers.indexOf(handler) >>> 0, 1);
            }
            return false;
        }
    }
    emit<Key extends keyof Events>(type: Key, ...eventParams: any[]) {
        const handlers = this.all.get(type);
        if (handlers) {
            return handlers.map((i) => {
                try {
                    return i.apply(this.bindThis, eventParams);
                } catch (err) {
                    console.warn('EventHub: ', err);
                    return null;
                }
            });
        } else {
            return [];
        }
    }
    once<Key extends keyof Events>(type: Key, handler: H) {
        //为事件注册单次监听器
        let wrapper: any = (...args: any[]) => {
            handler.apply(this.bindThis, args);
            this.off(type, wrapper);
        };
        this.singeOn(type, wrapper);
        return this;
    }
}
